\section{中断、异常处理入口程序}

\begin{minted}[breaklines=true, breakautoindent]{nasm}
%ifndef __INT_EXCEPT_ASM__
%define __INT_EXCEPT_ASM__

bits 32
global g_aIntExceptEntrypoint
extern DispatchIntExceptHandler

%define true 1
%define false 0

%define SUP_EFLAGS dword [esp + 24]
%define SUP_CS dword [esp + 20]
%define SUP_EIP dword [esp + 16]
%define SUP_ERROR_CODE dword [esp + 12]

%macro MAKE_INT_EXCEPT_ENTRYPOINT 3
section .data
%ifndef ONCE
%define ONCE
g_aIntExceptEntrypoint:
%endif
    dd IntExceptEntrypoint%1
section .text
IntExceptEntrypoint%1:
    %if %2 = false
        push dword 0 ; 额外压入错误码
    %endif
    test dword [esp + 8], 0x11 ; 判断：是否是从用户态进入中断
    jnz .save_context ; CS.CPL 非零，说明是从用户态进入中断
    sub esp, 8 ; 在内核态发生中断，CPU 不保存 SS ESP，预留位置存放 SS ESP
    push eax
    mov eax, SUP_ERROR_CODE
    mov dword [esp + 4], eax
    mov eax, SUP_EIP
    mov dword [esp + 8], eax
    mov eax, SUP_CS
    mov dword [esp + 12], eax
    mov eax, SUP_EFLAGS
    mov dword [esp + 16], eax
    mov eax, esp
    add eax, 28
    mov dword [esp + 20], eax
    mov eax, ss
    mov dword [esp + 24], eax
    pop eax
.save_context:
    push dword %1 ; 压入中断向量号
    push ds
    push es
    push fs
    push gs
    push eax
    push ecx
    push edx
    push ebp
    push ebx
    push esi
    push edi
    mov ax, 0x10
    mov ds, ax ; ds 指向内核数据段
    push esp
    call DispatchIntExceptHandler ; 执行中断处理
    add esp, 4
    pop edi
    pop esi
    pop ebx
    pop ebp
    pop edx
    pop ecx
    pop eax
    pop gs
    pop fs
    pop es
    pop ds
    add esp, 8 ; 跳过中断向量号和错误码
    test dword [esp + 4], 0x11 ; 是否返回到内核态
    jnz .return
    add esp, 20
    push dword [esp - 12]
    push dword [esp - 12]
    push dword [esp - 12]
.return:
    ; 0x20 ~ 0x27 为主片上产生的中断
    %if %1 >= 0x20 
        mov al, 0x20 ; 中断结束命令 EOI （End of Interupt）
        ; 0x28 ~ 0x2F 为从片上产生的中断，除了向主片发送 EOI，还需要向从片发送
        %if %1 >= 0x28 
            out 0xa0, al ; Slave Chip
        %endif
        out 0x20, al ; Master Chip
    %endif
    iret
%endmacro
; REGISTER_INT_EXCEPT_ENTRYPOINT(VECTOR)

MAKE_INT_EXCEPT_ENTRYPOINT 0x00, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x01, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x02, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x03, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x04, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x05, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x06, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x07, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x08, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x09, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x0A, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x0B, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x0C, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x0D, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x0E, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x0F, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x10, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x11, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x12, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x13, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x14, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x15, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x16, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x17, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x18, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x19, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x1A, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x1B, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x1C, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x1D, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x1E, true, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x1F, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x20, false, false
MAKE_INT_EXCEPT_ENTRYPOINT 0x21, false, false

%endif
\end{minted}